const LETTERS = /[a-z]/i;
const WHITESPACE = /\s/;
const NUMBERS = /[0-9]/;

const LeftParentheses = 'LeftParentheses'; // 左尖括号 <
const RightParentheses = 'RightParentheses'; // 右尖括号 >
const JSXIdentifier = 'JSXIdentifier'; // 标识符
const AttributeKey = 'AttributeKey'; // 元素属性 key
const AttributeValue = 'AttributeValue'; // 元素属性的值
const JSXText = 'JSXText'; // 字符串
const BackSlash = 'BackSlash'; // 反斜杠

let currentToken = {type: '', value: ''};

const tokens = [];
function emit(token) {
    currentToken = {type: '', value: ''};
    tokens.push(token);
}

function start (char) {
    if (char === '<') {
        emit({type: LeftParentheses, value: '<'});
        return foundLeftParentheses;
    }
    throw new Error('第一个字符必须是 < ');
}

function foundLeftParentheses(char) {
    if (LETTERS.test(char)) { // 小写字母
        currentToken.type = JSXIdentifier;
        currentToken.value += char;
        return jsxIdentifier; // 继续收集标识符
    } else if (char === '/') { // 标签结束 </h1>
        emit({type: BackSlash, value: '/'});
        return foundLeftParentheses;
    }

    throw new Error('第一个字符必须是 < ');
}

function jsxIdentifier(char) {
    if (NUMBERS.test(char) || LETTERS.test(char)) { // 数字
        currentToken.value += char;
        return jsxIdentifier;
    } else if (WHITESPACE.test(char)) { // 空格，表示标识符结束
        emit(currentToken);
        return attribute;
    } else if (char === '>') { // 没有属性了，且是 ”>“, 就结束
        emit(currentToken);
        emit({type: RightParentheses, value: '>'});
        return foundRightParentheses; // 继续找右尖括号
    }
    throw new Error('第一个字符必须是 < ');
}

function attribute(char) {
    if (LETTERS.test(char)) {
        currentToken.type = AttributeKey;
        currentToken.value += char;
        return attributeKey;
    }
    throw new Error('属性处理有错');
}

function attributeKey(char) {
    if (LETTERS.test(char) || NUMBERS.test(char)) { // 小写字母或者数字
        currentToken.value += char;
        return attributeKey;
    } else if (char === '=') { // 遇到等号 = ，表示结束， id=
        emit(currentToken);
        return attributeValue; // 开始找属性对应的值
    }
    throw new Error('属性或者等号处理有错');
}

function attributeValue (char) {
    if(char === '"') { // 前双引号
        currentToken.type = AttributeValue;
        currentToken.value = '';
        return attributeStringValue; // 找属性对应的值
    }
    throw new Error('属性值的前置双引号处理有错');
}

function attributeStringValue(char) {
    if(LETTERS.test(char) || NUMBERS.test(char)) { // 小写字母或者数字
        currentToken.value += char;
        return attributeStringValue;// 继续找属性对应的值
    } else if (char === '"') { // 后双引号， 结束
        emit(currentToken);
        return tryLeaveAttribute; // 是否是新属性，或者是标签结束
    }
    throw new Error('属性处理有错');
}

function tryLeaveAttribute(char) {
    if (WHITESPACE.test(char)) { // 还有属性
        return attribute;
    } else if (char === '>') { // 开始标签结束 <h1 id="title" >
        emit({type: RightParentheses, value: '>'});
        return foundRightParentheses;
    }
    throw new Error('属性值或是结束标签 > 处理有错');
}

function foundRightParentheses (char) {
    if (char === '<') { // 新的标签开始了
        emit({type: LeftParentheses, value: '<'});
        return foundLeftParentheses;
    } else {
        currentToken.type = JSXText;
        currentToken.value += char;
        return jsxText;
    }
}

function jsxText(char) {
    if (char === '<') {
        emit(currentToken);
        emit({type: LeftParentheses, value: '<'});
        return foundLeftParentheses;
    } else {
        currentToken.value += char;
        return jsxText;
    }
}

function tokenizer (input) {
    let state = start; // 开始处于的状态

    for (const char of input) {
        if (state) {
            state = state(char);
        }
    }

    return tokens;
}

module.exports = {
    tokenizer
}

const sourceCode = '<h1 id="title"><span>hello</span>world</h1>'
console.log(tokenizer(sourceCode));
/*
[
    { type: 'LeftParentheses', value: '<' },
    { type: 'JSXIdentifier', value: 'h1' },
    { type: 'AttributeKey', value: 'id' },
    { type: 'AttributeValue', value: 'title' },
    { type: 'RightParentheses', value: '>' },
    { type: 'LeftParentheses', value: '<' },
    { type: 'JSXIdentifier', value: 'span' },
    { type: 'RightParentheses', value: '>' },
    { type: 'JSXText', value: 'hello' },
    { type: 'LeftParentheses', value: '<' },
    { type: 'BackSlash', value: '/' },
    { type: 'JSXIdentifier', value: 'span' },
    { type: 'RightParentheses', value: '>' },
    { type: 'JSXText', value: 'world' },
    { type: 'LeftParentheses', value: '<' },
    { type: 'BackSlash', value: '/' },
    { type: 'JSXIdentifier', value: 'h1' },
    { type: 'RightParentheses', value: '>' }
]
*/